import EventManager from './EventManager';
import ResManager from './ResManager';
import BaseUI from '../base/BaseUI';
import { GameEvent } from '../../game/data/GameConst';
import { Label, Node, Prefab, UIOpacity, Vec3, instantiate, Tween } from 'cc';
import { UI_CONFIG } from '../../game/AssetsConfig';
export type UIConfig = {
  path: string;
  parent: string;
  name: string;
};

type QueueElement = {
  ui: UIConfig;
  args: any[];
};

class PriorityQueue {
  private queue: QueueElement[][] = [];
  enqueue(element: QueueElement, priority: number) {
    let arr = this.queue[priority];
    if (!arr) arr = [];
    arr.push(element);
    this.queue[priority] = arr;
  }

  dequeue(): QueueElement {
    for (const element of this.queue) {
      if (element && element.length > 0) return element.shift();
    }
    return null;
  }
}

// 单例ui
class UIManager {
  private static instance: UIManager;
  public static get Ins() {
    if (!this.instance) this.instance = new UIManager();
    return this.instance;
  }
  private constructor() {}
  public static clear() {
    this.instance = null;
  }

  panelLayer: Node = null;
  uiTipLayer: Node = null;
  popupLayer: Node = null;
  uiTopLayer: Node = null;
  tipLayer: Node = null;

  private opeded = {};
  private prefabs: { [key: string]: Prefab } = {};
  private popUpPriority = {
    // [UI_CONFIG.HOME_PANEL.name]: 100,
    // [UI_CONFIG.TEST_POPUP_1.name]: 1,
    // [UI_CONFIG.TEST_POPUP_2.name]: 2,
    // [UI.MAZE.name]: 100,
    // [UI.GUIDE.name]: 100,
    // [UI.PLOT.name]: 100,
    // [UI.HAPPY_HOUSE.name]: 100,
    // [UI.CHAT_HINT.name]: 5,
    // [UI.CHAT.name]: 5,
    // [UI.TALK.name]: 5,
  };
  private currentPriority: number;
  private priorityQueue: PriorityQueue = new PriorityQueue();
  // 正在打开的界面
  private opening = {};

  async open(ui: UIConfig, ...args) {
    let name = ui.name;
    let priority = this.getPriority(name);
    if (priority > this.currentPriority) {
      this.priorityQueue.enqueue({ ui: ui, args: args }, priority);
      return;
    }
    this.currentPriority = priority;

    if (this.opening[name]) {
      console.log('正在打开中', name);
      return;
    }

    if (this.opeded[name]) {
      let script = this.opeded[name].getComponent(BaseUI);
      script.initData.apply(script, args);
      return;
    }
    this.opening[name] = true;

    let prefab = this.prefabs[name];
    if (!prefab) {
      prefab = await ResManager.Ins.load(ui.path, Prefab);
      if (!prefab) {
        delete this.opening[name];
        return;
      }
      this.prefabs[name] = prefab;
    }
    let node = instantiate(prefab);
    this[ui.parent].addChild(node);
    this.opeded[name] = node;
    delete this.opening[name];

    if (ui.parent === 'panelLayer') {
      for (let i = 0; i < this[ui.parent].children.length; i++) {
        this[ui.parent].children[i].active = i === this[ui.parent].children.length - 1;
      }
    }

    let script = node.getComponent(BaseUI);
    if (!script) {
      console.log(`${node.name}   未绑定脚本`);
    } else {
      script.initData.apply(script, args);
    }

    EventManager.Ins.emit(GameEvent.UPDATE_UI_LAYER);
  }

  getFirstUIName() {
    let name;
    if (this.popupLayer.children.length > 0) {
      name = this.popupLayer.children[this.popupLayer.children.length - 1].name;
    } else if (this.panelLayer.children.length > 0) {
      name = this.panelLayer.children[this.panelLayer.children.length - 1].name;
    }
    return name;
  }

  public close(ui: UIConfig, showTween = false, uiNode?: Node) {
    let name = ui.name;
    let node: Node = this.opeded[name];
    if (!node) {
      console.log('页面未打开，无需关闭');
      return;
    }
    delete this.opeded[name];
    EventManager.Ins.emit(GameEvent.CLOSE_UI, name);
    if (!node) {
      this.destroyUI(uiNode);
      return;
    }
    let caller = node.getComponent(BaseUI);
    EventManager.Ins.offCaller(caller);
    if (!showTween) {
      this.destroyUI(node);
      return;
    }
    new Tween(node)
      .to(0.1, { opacityEx: 0, scaleEx: 1.3 })
      .call(() => {
        this.destroyUI(node);
      })
      .start();
  }

  private destroyUI(node: Node) {
    let parent = node.parent;
    node.removeFromParent();
    node.destroy();

    this.currentPriority = this.getPriority(this.getFirstUIName());
    let element = this.priorityQueue.dequeue();
    if (element) {
      let { ui, args } = element;
      this.open(ui, ...args);
    }

    if (parent.name === 'panelLayer') {
      let layer = 'panelLayer';
      for (let i = 0; i < this[layer].children.length; i++) {
        this[layer].children[i].active = i === this[layer].children.length - 1;
      }
    }
    EventManager.Ins.emit(GameEvent.UPDATE_UI_LAYER);
    // if (Object.keys(this.opeded).length == 1) EventManager.Ins.emit(GameEvent.SHOW_CHAT_HINT);
  }

  public isOpened(ui: UIConfig) {
    if (this.opeded[ui.name]) return true;
    return false;
  }

  private tipNode: Node = null;
  public async showTip(text: string) {
    if (!this.tipNode) {
      let prefab: Prefab = await ResManager.Ins.load(UI_CONFIG.TEXT_TIP.path, Prefab);
      this.tipNode = instantiate(prefab);
      this.tipLayer.addChild(this.tipNode);
    }
    this.tipNode.getChildByName('txtTip').getComponent(Label).string = text;
    this.tipNode.opacityEx = 255;
    Tween.stopAllByTarget(this.tipNode);
    new Tween(this.tipNode).delay(1).to(1, { opacityEx: 0 }).start();
  }

  getLayerShowUINum(parentName: string) {
    return this[parentName].children.length;
  }

  isOnHome() {
    if (this.popupLayer.children.length) return false;
    if (this.uiTopLayer.children.length) return false;
    // if (this.panelLayer.children.length == 1 && this.panelLayer.children[0].name == UI_CONFIG.HOME_PANEL.name) return true;
    return false;
  }

  getPriority(name: string) {
    return this.popUpPriority[name] ? this.popUpPriority[name] : 0;
  }
}
export default UIManager;
